1 using System;
2 using
System.Collections.Generic;
3 using
System.Text;
4
5 namespace
VietGraph
6 {
7     
public class Expression : IEvaluatable
8     {
9         
string text = "";
10         
string textInternal = "";
11         
bool isValid = false;
12         
char charX = 'x';
13         System.Collections.Generic.Dictionary<
string, double> constants;
14
15         
public Expression(string expressionText)
16         {
17             
this.constants = new Dictionary<string, double>();
18             
this.constants.Add("pi", Math.PI);
19             
this.constants.Add("e", Math.E);
20             
this.ExpressionText = expressionText;
21         }
22
23         
#region Public Properties for IEvaluatable
24
25
26         
public string ExpressionText
27         {
28             
get
29             {
30                 
return this.text;
31             }
32             
set
33             {
34                 
this.text = value;
35                 
this.textInternal = "(" + value + ")";
36                 
this.textInternal = InsertPrecedenceBrackets().Trim();
37                 
this.Validate();
38             }
39         }
40
41         
public bool IsValid
42         {
43             
get
44             {
45                 
return this.isValid;
46             }
47         }
48         
#endregion
49
50         
#region Public Methods for IEvaluatable
51
52         
public double Evaluate(double dvalueX)
53         {
54             
if (this.isValid == false)
55                 
return Double.NaN;
56             
int temp;
57             
return EvaluateInternal(dvalueX, 0, out temp);
58         }
59
60         
#endregion
61
62         
#region Private Methods
63
64         
private void Validate()
65         {
66             
try
67             {
68                 
int temp;
69                 
//if expression does not throw an exception when evaluated at "1", we assume it to be valid
70                 EvaluateInternal(
1, 0, out temp);
71                 
this.isValid = true;
72             }
73             
catch (FormatException)
74             {
75                 
this.isValid = false;
76             }
77             
catch (System.Collections.Generic.KeyNotFoundException)
78             {
79                 
this.isValid = false;
80             }
81
82         }
83
84         
static bool IsOperator(char character)
85         {
86             
if (character == '+' || character == '-' || character == '*'
87                 || character ==
'/' || character == '^' || character == '%')
88                 
return true;
89             
return false;
90
91         }
92
93         
public double EvaluateInternal(double dvalueX, int startIndex, out int endIndex)
94         {
95             
//exceptions are bubbled up
96
97             
//dAnswer is the running total
98             
double dAnswer = 0, dOperand = 0;
99             
char chCurrentChar, chOperator = '+';
100             
string strAngleOperator;
101
102             
for (int i = startIndex + 1; i < textInternal.Length; i++)
103             {
104                 startIndex = i;
105                 chCurrentChar = textInternal[startIndex];
106
107                 
// if found a number, update dOperand
108                 
if (char.IsDigit(chCurrentChar))
109                 {
110                     
while (char.IsDigit(textInternal[i]) || textInternal[i] == '.')
111                         i++;
112                     dOperand = Convert.ToDouble(textInternal.Substring(startIndex, i - startIndex));
113                     i--;
114                 }
115                 
//if found an operator
116                 
else if (IsOperator(chCurrentChar))
117                 {
118                     dAnswer = DoOperation(dAnswer, dOperand, chOperator);
119                     chOperator = chCurrentChar;
120                 }
121                 
//if found independent variable
122                 
else if (char.ToLower(chCurrentChar) == charX)
123                 {
124                     dOperand = dvalueX;
125                 }
126                 
//if found a bracket, solve it first
127                 
else if (chCurrentChar == '(')
128                 {
129                     dOperand = EvaluateInternal(dvalueX, i,
out endIndex);
130                     i = endIndex;
131                 }
132                 
//if found closing bracket, return result
133                 
else if (chCurrentChar == ')')
134                 {
135                     dAnswer = DoOperation(dAnswer, dOperand, chOperator);
136                     endIndex = i;
137                     
return dAnswer;
138                 }
139
140                 
else //could be any function e.g. "sin" or any constant e.g "pi"
141                 {
142                     
while (char.IsLetter(textInternal[i]))
143                         i++;
144                     
//if we got letters followed by "(", we've got a function else a constant
145                     
if (textInternal[i] == '(')
146                     {
147                         strAngleOperator = textInternal.Substring(startIndex, i - startIndex).ToLower();
148                         dOperand = EvaluateInternal(dvalueX, i,
out endIndex);
149                         i = endIndex;
150                         dOperand = DoAngleOperation(dOperand, strAngleOperator);
151                     }
152                     
else //constant
153                     {
154                         dOperand =
this.constants[textInternal.Substring(startIndex, i - startIndex).ToLower()];
155                         i--;
156                     }
157                 }
158                 
if (double.IsNaN(dAnswer) || double.IsNaN(dOperand))
159                 {
160                     endIndex = i;
161                     
return double.NaN;
162                 }
163             }
164             endIndex = textInternal.Length;
165             
return 0;
166         }
167
168         
//this function contains definitions for supported functions, we can add more also.
169         
static double DoAngleOperation(double dOperand, string strOperator)
170         {
171             
const double pi = 3.1415926535897932384626433832795;
172             strOperator = strOperator.ToLower();
173             
switch (strOperator)
174             {
175                 
case "abs":
176                     
if (ExpressionHelper.BlnRadian)
177                     {
178                         
return Math.Abs(dOperand);
179                     }
180                     
else
181                     {
182                         
return Math.Abs(dOperand*pi/180);
183                     }
184                 
case "sin":
185                     
if (ExpressionHelper.BlnRadian)
186                     {
187                         
return Math.Sin(dOperand);
188                     }
189                     
else
190                     {
191                         
return Math.Sin(dOperand*pi/180);
192                     }
193                 
case "cos":
194                     
if (ExpressionHelper.BlnRadian)
195                     {
196                         
return Math.Cos(dOperand);
197                     }
198                     
else
199                     {
200                         
return Math.Cos(dOperand*pi/180);
201                     }
202                 
case "tan":
203                     
if (ExpressionHelper.BlnRadian)
204                     {
205                         
return Math.Tan(dOperand);
206                     }
207                     
else
208                     {
209                         
return Math.Tan(dOperand*pi/180);
210                     }
211                 
case "sec":
212                     
if (ExpressionHelper.BlnRadian)
213                     {
214                         
return 1.0 / Math.Cos(dOperand);
215                     }
216                     
else
217                     {
218                         
return 1.0 / Math.Cos(dOperand*pi/180);
219                     }
220                 
case "cosec":
221                     
if (ExpressionHelper.BlnRadian)
222                     {
223                         
return 1.0 / Math.Sin(dOperand);
224                     }
225                     
else
226                     {
227                         
return 1.0 / Math.Sin(dOperand*pi/180);
228                     }
229                 
case "cot":
230                     
if (ExpressionHelper.BlnRadian)
231                     {
232                         
return 1.0 / Math.Tan(dOperand);
233                     }
234                     
else
235                     {
236                         
return 1.0 / Math.Tan(dOperand*pi/180);
237                     }
238                 
case "arcsin":
239                     
if (ExpressionHelper.BlnRadian)
240                     {
241                         
return Math.Asin(dOperand);
242                     }
243                     
else
244                     {
245                         
return Math.Asin(dOperand*pi/180);
246                     }
247                 
case "arccos":
248                     
if (ExpressionHelper.BlnRadian)
249                     {
250                         
return Math.Acos(dOperand);
251                     }
252                     
else
253                     {
254                         
return Math.Acos(dOperand*pi/180);
255                     }
256                 
case "arctan":
257                     
if (ExpressionHelper.BlnRadian)
258                     {
259                         
return Math.Atan(dOperand);
260                     }
261                     
else
262                     {
263                         
return Math.Atan(dOperand*pi/180);
264                     }
265                 
case "exp":
266                     
if (ExpressionHelper.BlnRadian)
267                     {
268                         
return Math.Exp(dOperand);
269                     }
270                     
else
271                     {
272                         
return Math.Exp(dOperand*pi/180);
273                     }
274                 
case "ln":
275                     
if (ExpressionHelper.BlnRadian)
276                     {
277                         
return Math.Log(dOperand);
278                     }
279                     
else
280                     {
281                         
return Math.Log(dOperand*pi/180);
282                     }
283                 
case "log":
284                     
if (ExpressionHelper.BlnRadian)
285                     {
286                         
return Math.Log10(dOperand);
287                     }
288                     
else
289                     {
290                         
return Math.Log10(dOperand*pi/180);
291                     }
292                 
case "antilog":
293                     
if (ExpressionHelper.BlnRadian)
294                     {
295                         
return Math.Pow(10, dOperand);
296                     }
297                     
else
298                     {
299                         
return Math.Pow(10, dOperand)*pi/180;
300                     }
301                 
case "sqrt":
302                     
if (ExpressionHelper.BlnRadian)
303                     {
304                         
return Math.Sqrt(dOperand);
305                     }
306                     
else
307                     {
308                         
return Math.Sqrt(dOperand*pi/180);
309                     }
310
311                 
case "sinh":
312                     
if (ExpressionHelper.BlnRadian)
313                     {
314                         
return Math.Sinh(dOperand);
315                     }
316                     
else
317                     {
318                         
return Math.Sinh(dOperand*pi/180);
319                     }
320                 
case "cosh":
321                     
if (ExpressionHelper.BlnRadian)
322                     {
323                         
return Math.Cosh(dOperand);
324                     }
325                     
else
326                     {
327                         
return Math.Cosh(dOperand*pi/180);
328                     }
329                 
case "tanh":
330                     
if (ExpressionHelper.BlnRadian)
331                     {
332                         
return Math.Tanh(dOperand);
333                     }
334                     
else
335                     {
336                         
return Math.Tanh(dOperand*pi/180);
337                     }
338                 
case "arcsinh":
339                     
if (ExpressionHelper.BlnRadian)
340                     {
341                         
return Math.Log(dOperand + Math.Sqrt(dOperand * dOperand + 1));
342                     }
343                     
else
344                     {
345                         
return Math.Log(dOperand + Math.Sqrt((dOperand * dOperand + 1)*pi/180));
346                     }
347                 
case "arccosh":
348                     
if (ExpressionHelper.BlnRadian)
349                     {
350                         
return Math.Log(dOperand + Math.Sqrt(dOperand * dOperand - 1));
351                     }
352                     
else
353                     {
354                         
return Math.Log(dOperand + Math.Sqrt((dOperand * dOperand - 1)*pi/180));
355                     }
356                 
case "arctanh":
357                     
if (ExpressionHelper.BlnRadian)
358                     {
359                         
return Math.Log((1 + dOperand) / (1 - dOperand)) / 2;
360                     }
361                     
else
362                     {
363                         
return Math.Log(((1 + dOperand) / (1 - dOperand)) * pi / 180) / 2;
364                     }
365                 
default:
366                     
//throw new ArgumentException("InvalidAngleOperatorException");
367                     
return double.NaN;
368             }
369         }
370
371         
// returns dOperant1 (op) dOperand2
372         
static double DoOperation(double dOperand1, double dOperand2, char chOperator)
373         {
374             
switch (chOperator)
375             {
376                 
case '+':
377                     
return dOperand1 + dOperand2;
378                 
case '-':
379                     
return dOperand1 - dOperand2;
380                 
case '*':
381                     
return dOperand1 * dOperand2;
382                 
case '/':
383                     
return dOperand1 / dOperand2;
384                 
case '^':
385                     
return Math.Pow(dOperand1, dOperand2);
386                 
case '%':
387                     
return dOperand1 % dOperand2;
388             }
389             
return double.NaN;
390         }
391
392         
//insert brackets at appropriate positions since the evaluation function
393         
// only evaluates from Left To Right considering only bracket's precedence
394         
string InsertPrecedenceBrackets()
395         {
396             
int i = 0, j = 0;
397             
int iBrackets = 0;
398             
bool bReplace = false;
399             
int iLengthExpression;
400             
string strExpression = this.textInternal;
401
402             
//Precedence for * && /
403             i =
1;
404             iLengthExpression = strExpression.Length;
405             
while (i <= iLengthExpression)
406             {
407                 
if (strExpression.Substring(-1 + i, 1) == "*" || strExpression.Substring(-1 + i, 1) == "/")
408                 {
409                     
for (j = i - 1; j > 0; j--)
410                     {
411                         
if (strExpression.Substring(-1 + j, 1) == ")")
412                             iBrackets = iBrackets +
1;
413                         
if (strExpression.Substring(-1 + j, 1) == "(")
414                             iBrackets = iBrackets -
1;
415                         
if (iBrackets < 0)
416                             
break;
417                         
if (iBrackets == 0)
418                         {
419                             
if (strExpression.Substring(-1 + j, 1) == "+" || strExpression.Substring(-1 + j, 1) == "-")
420                             {
421                                 strExpression = strExpression.Substring(-
1 + 1, j) + "(" + strExpression.Substring(-1 + j + 1);
422                                 bReplace =
true;
423                                 i = i +
1;
424                                 
break;
425                             }
426                         }
427                     }
428                     iBrackets =
0;
429                     j = i;
430                     i = i +
1;
431                     
while (bReplace == true)
432                     {
433                         j = j +
1;
434                         
if (strExpression.Substring(-1 + j, 1) == "(")
435                             iBrackets = iBrackets +
1;
436                         
if (strExpression.Substring(-1 + j, 1) == ")")
437                         {
438                             
if (iBrackets == 0)
439                             {
440                                 strExpression = strExpression.Substring(-
1 + 1, j - 1) + ")" + strExpression.Substring(-1 + j);
441                                 bReplace =
false;
442                                 i = i +
1;
443                                 
break;
444                             }
445                             
else
446                                 iBrackets = iBrackets -
1;
447                         }
448                         
if (strExpression.Substring(-1 + j, 1) == "+" || strExpression.Substring(-1 + j, 1) == "-")
449                         {
450                             strExpression = strExpression.Substring(-
1 + 1, j - 1) + ")" + strExpression.Substring(-1 + j);
451                             bReplace =
false;
452                             i = i +
1;
453                             
break;
454                         }
455                     }
456                 }
457
458                 iLengthExpression = strExpression.Length;
459                 i = i +
1;
460             }
461
462
463             
//Precedence for ^ && %
464             i =
1;
465             iLengthExpression = strExpression.Length;
466             
while (i <= iLengthExpression)
467             {
468                 
if (strExpression.Substring(-1 + i, 1) == "^" || strExpression.Substring(-1 + i, 1) == "%")
469                 {
470                     
for (j = i - 1; j > 0; j--)
471                     {
472                         
if (strExpression.Substring(-1 + j, 1) == ")")
473                             iBrackets = iBrackets +
1;
474                         
if (strExpression.Substring(-1 + j, 1) == "(")
475                             iBrackets = iBrackets -
1;
476                         
if (iBrackets < 0)
477                             
break;
478                         
if (iBrackets == 0)
479                         {
480                             
if (strExpression.Substring(-1 + j, 1) == "+"
481                                 || strExpression.Substring(-
1 + j, 1) == "-"
482                                 || strExpression.Substring(-
1 + j, 1) == "*"
483                                 || strExpression.Substring(-
1 + j, 1) == "/")
484                             {
485                                 strExpression = strExpression.Substring(-
1 + 1, j) + "(" + strExpression.Substring(-1 + j + 1);
486                                 bReplace =
true;
487                                 i = i +
1;
488                                 
break;
489                             }
490                         }
491                     }
492                     iBrackets =
0;
493                     j = i;
494                     i = i +
1;
495                     
while (bReplace == true)
496                     {
497                         j = j +
1;
498                         
if (strExpression.Substring(-1 + j, 1) == "(")
499                             iBrackets = iBrackets +
1;
500                         
if (strExpression.Substring(-1 + j, 1) == ")")
501                         {
502                             
if (iBrackets == 0)
503                             {
504                                 strExpression = strExpression.Substring(-
1 + 1, j - 1) + ")" + strExpression.Substring(-1 + j);
505                                 bReplace =
false;
506                                 i = i +
1;
507                                 
break;
508                             }
509                             
else
510                                 iBrackets = iBrackets -
1;
511                         }
512                         
if (strExpression.Substring(-1 + j, 1) == "+" || strExpression.Substring(-1 + j, 1) == "-"
513                             || strExpression.Substring(-
1 + j, 1) == "*" || strExpression.Substring(-1 + j, 1) == "/")
514                         {
515                             strExpression = strExpression.Substring(-
1 + 1, j - 1) + ")" + strExpression.Substring(-1 + j);
516                             bReplace =
false;
517                             i = i +
1;
518                             
break;
519                         }
520                     }
521                 }
522                 iLengthExpression = strExpression.Length;
523                 i = i +
1;
524             }
525             
return strExpression;
526         }
527
528         
static double GetR(double X, double Y)
529         {
530             
return Math.Sqrt(X * X + Y * Y);
531         }
532
533         
static double GetTheta(double X, double Y)
534         {
535             
double dTheta;
536             
if (X == 0)
537             {
538                 
if (Y > 0)
539                     dTheta = Math.PI /
2;
540                 
else
541                     dTheta = -Math.PI /
2;
542             }
543             
else
544                 dTheta = Math.Atan(Y / X);
545
546             
//actual range of theta is from 0 to 2PI
547             
if (X < 0)
548                 dTheta = dTheta + Math.PI;
549             
else if (Y < 0)
550                 dTheta = dTheta +
2 * Math.PI;
551             
return dTheta;
552         }
553
554         
#endregion
555
556     }
557 }



Phần mềm vẽ đồ thị C# 6.567 lượt xem

Gõ tìm kiếm nhanh...